package com.gaojinqi.sys.core.shiro.matcher;

import com.gaojinqi.base.common.exception.AuthException;
import com.gaojinqi.base.common.exception.AuthExpiredException;
import com.gaojinqi.sys.core.shiro.util.JwtTokenHelper;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Objects;

/**
 * Jwt 密码匹配器
 *
 * @author gaojinqi
 * @version 1.0
 * @since 2020年05月14日
 */
@Slf4j
public class JwtCredentialsMatcher implements CredentialsMatcher {

    @Autowired
    private JwtTokenHelper jwtTokenHelper;

    public void setJwtTokenHelper(JwtTokenHelper jwtTokenHelper) {
        this.jwtTokenHelper = jwtTokenHelper;
    }

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String userName = (String) token.getPrincipal();
        if (!Objects.equals(userName, info.getCredentials())) {
            throw new AuthenticationException("登录令牌不正确");
        }
        String jwt = (String) token.getCredentials();
        if (jwtTokenHelper != null) {
            String jwtCache = jwtTokenHelper.getTokenCache(userName);
            if (jwtCache == null) {
                log.warn("缓存中不存在该用户令牌 userName = {}", userName);
                throw new AuthException();
            }
            if (!Objects.equals(jwtCache, jwt)) {
                log.warn("缓存中令牌与登录令牌不一致，缓存令牌 = {}，登录令牌 = {}", jwtCache, jwt);
                throw new AuthException();
            }
        }
        try {
            Claims claims = jwtTokenHelper.verifyToken(jwt);
        } catch (UnsupportedJwtException | MalformedJwtException | SignatureException | IllegalArgumentException e) {
            log.warn("jwt token 认证错误", e);
            throw new AuthException("令牌错误");
        } catch (ExpiredJwtException e) {
            log.warn("jwt token 超时", e);
            throw new AuthExpiredException("令牌超时");
        } catch (JwtException e) {
            log.warn("jwt token 认证错误，JwtException...", e);
            throw new AuthException("令牌错误");
        } catch (Exception e) {
            log.warn("jwt token 认证错误，Exception...", e);
            throw new AuthException("令牌错误");
        }
        return true;
    }

}
